import { Injectable } from '@nestjs/common';
import { and, eq, ilike, ne } from 'drizzle-orm';
import { sysRole, sysRoleMenu, sysUserRole, BaseService, db, type SysRole } from '@nbase/db';
import { BizException } from '@nbase/nest-mods';
import { SYSTEM_ROLE, type IRole, type IPaginationResponse } from '@nbase/shared';
import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { QueryRoleDto } from './dto/query-role.dto';
import { AssignPermissionsDto } from './dto/assign-permissions.dto';
import { AssignUsersDto } from './dto/assign-users.dto';
import { toRole, toRolePage } from './role.mapper';

/**
 * 角色服务
 */
@Injectable()
export class RoleService extends BaseService<typeof sysRole> {
  constructor() {
    super(sysRole);
  }

  /**
   * 创建角色
   */
  async createRole(createRoleDto: CreateRoleDto): Promise<IRole> {
    // 检查 code 是否已存在
    const isExist = await this.exists(eq(sysRole.code, createRoleDto.code));
    if (isExist) {
      throw BizException.roleExist();
    }

    const created = await this.create(createRoleDto);
    return toRole(created as SysRole);
  }

  /**
   * 更新角色
   */
  async updateRole(id: string, updateRoleDto: UpdateRoleDto): Promise<IRole> {
    // 检查是否为超级管理员角色
    const role = await this.findById(id);
    if (role && (role as SysRole).code === SYSTEM_ROLE.SUPER_ADMIN) {
      throw BizException.operationFailed('超级管理员角色是系统内置角色，不允许修改');
    }

    // 如果更新 code，检查是否已存在
    if (updateRoleDto.code) {
      const existing = await this.findOne(eq(sysRole.code, updateRoleDto.code));
      if (existing && existing.id !== id) {
        throw BizException.roleExist();
      }
    }

    const updated = await this.update(id, updateRoleDto);
    return toRole(updated as SysRole);
  }

  /**
   * 删除角色
   */
  async deleteRole(id: string): Promise<void> {
    // 检查是否为超级管理员角色
    const role = await this.findById(id);
    if (role && (role as SysRole).code === SYSTEM_ROLE.SUPER_ADMIN) {
      throw BizException.operationFailed('超级管理员角色是系统内置角色，不允许删除');
    }

    // 检查是否有用户使用该角色
    const userRoles = await db
      .select()
      .from(sysUserRole)
      .where(eq(sysUserRole.roleId, id))
      .limit(1);

    if (userRoles.length > 0) {
      throw BizException.roleInUse();
    }

    await this.softDelete(id);
  }

  /**
   * 分页查询角色
   */
  async paginateRoles(query: QueryRoleDto): Promise<IPaginationResponse<IRole>> {
    const conditions = [];

    // 始终排除超级管理员角色
    conditions.push(ne(sysRole.code, SYSTEM_ROLE.SUPER_ADMIN));

    if (query.code) {
      conditions.push(ilike(sysRole.code, `%${query.code}%`));
    }
    if (query.name) {
      conditions.push(ilike(sysRole.name, `%${query.name}%`));
    }
    if (query.status !== undefined) {
      conditions.push(eq(sysRole.status, query.status));
    }

    const where = conditions.length > 0 ? and(...conditions) : undefined;
    const result = await this.paginate(query, where);
    return toRolePage(result as IPaginationResponse<SysRole>);
  }

  /**
   * 根据 code 查找角色
   */
  async findByCode(code: string): Promise<IRole | null> {
    const role = (await this.findOne(eq(sysRole.code, code))) as SysRole | undefined;
    return role ? toRole(role) : null;
  }

  /**
   * 为角色分配权限（菜单）
   */
  async assignPermissions(roleId: string, assignPermissionsDto: AssignPermissionsDto): Promise<void> {
    // 检查角色是否存在
    const role = await this.findById(roleId);
    if (!role) {
      throw BizException.roleNotFound();
    }

    // 检查是否为超级管理员角色
    if ((role as SysRole).code === SYSTEM_ROLE.SUPER_ADMIN) {
      throw BizException.operationFailed('超级管理员角色是系统内置角色，拥有所有权限，不允许修改权限');
    }

    const userId = this.getUserId();

    // 使用事务：先删除旧权限，再添加新权限
    await db.transaction(async (tx) => {
      // 1. 删除旧权限
      await tx.delete(sysRoleMenu).where(eq(sysRoleMenu.roleId, roleId));

      // 2. 添加新权限
      if (assignPermissionsDto.menuIds.length > 0) {
        const values = assignPermissionsDto.menuIds.map((menuId) => ({
          roleId,
          menuId,
          createdBy: userId,
        }));
        await tx.insert(sysRoleMenu).values(values);
      }
    });
  }

  /**
   * 获取角色的权限（菜单 ID 列表）
   */
  async getRolePermissions(roleId: string): Promise<string[]> {
    const permissions = await db
      .select({
        menuId: sysRoleMenu.menuId,
      })
      .from(sysRoleMenu)
      .where(eq(sysRoleMenu.roleId, roleId));

    return permissions.map((p) => p.menuId);
  }

  /**
   * 为角色分配用户
   */
  async assignUsers(roleId: string, assignUsersDto: AssignUsersDto): Promise<void> {
    // 检查角色是否存在
    const role = await this.findById(roleId);
    if (!role) {
      throw BizException.roleNotFound();
    }

    // 检查是否为超级管理员角色
    if ((role as SysRole).code === SYSTEM_ROLE.SUPER_ADMIN) {
      throw BizException.operationFailed('超级管理员角色是系统内置角色，不允许手动分配用户');
    }

    const userId = this.getUserId();

    // 使用事务：先删除该角色的所有用户关联，再添加新的用户关联
    await db.transaction(async (tx) => {
      // 1. 删除该角色的所有用户关联
      await tx.delete(sysUserRole).where(eq(sysUserRole.roleId, roleId));

      // 2. 添加新的用户关联
      if (assignUsersDto.userIds.length > 0) {
        const values = assignUsersDto.userIds.map((uid) => ({
          userId: uid,
          roleId,
          createdBy: userId,
        }));
        await tx.insert(sysUserRole).values(values);
      }
    });
  }

  /**
   * 获取角色的用户（用户 ID 列表）
   */
  async getRoleUsers(roleId: string): Promise<string[]> {
    const roleUsers = await db
      .select({
        userId: sysUserRole.userId,
      })
      .from(sysUserRole)
      .where(eq(sysUserRole.roleId, roleId));

    return roleUsers.map((ru) => ru.userId);
  }
}

